/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */

package org.huihoo.orbas.orb;

/**
 * <p>Description: </p>
 * ORB main class.
 * <p>Copyright (c) 2002,2003</p>
 * <p>Company: <a href="http://www.huihoo.org/">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~mep">mep(mep@huihoo.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

import org.huihoo.orbas.orb.cdr.CDROutputStream;
import org.huihoo.orbas.orb.ior.IorParser;
import org.huihoo.orbas.orb.protocols.Listener;
import org.huihoo.orbas.orb.protocols.ProfileRegistry;
import org.huihoo.orbas.orb.protocols.ServerBroadcaster;
import org.huihoo.orbas.orb.protocols.Transport;
import org.huihoo.orbas.orb.protocols.TransportsPool;
import org.huihoo.orbas.orb.thread.RequestQueue;
import org.huihoo.orbas.orb.thread.ServerWorkerRegistry;
import org.huihoo.orbas.poa.OrbasPoa;
import org.huihoo.orbas.util.Logger;
import org.huihoo.orbas.util.LoggerFactory;

//import org.omg.PortableServer.POA;

/**
 * testcase test.org.huihoo.orbas.orb.TestORB
 */
public class ORB extends ORBSingleton {
	private Hashtable initialReferences = new Hashtable();
	private Hashtable valueFactories = new Hashtable();
	private static final String[] services = { "RootPOA", "NameService" };
	private java.util.Hashtable serverBroadcasterFactory = new Hashtable();

	private OrbasPoa rootPoa;
	private ProfileRegistry profileDealers;
	private TransportsPool pool;
	private IopEngine invoker;
	private RequestQueue queue;
	private ServerWorkerRegistry handler;
	private Listener listener;
	private ServerBroadcaster broadcaster;
	private java.lang.Thread casterThread;
	private java.util.Hashtable poaTable;

	private static Logger logger = LoggerFactory.getLogger("ORB");

	public ORB() {
	}

	public void initialize() {
		logger.debug("ORB::initialize()");

		profileDealers = new ProfileRegistry();
		pool = new TransportsPool(this);

		org.huihoo.orbas.orb.protocols.iiop.IiopProtocolInitializer.setup(this);
		invoker = new IopEngine(this);

		queue = new RequestQueue(this);
		handler = new ServerWorkerRegistry(this);
		listener = new Listener(this);
		poaTable = new java.util.Hashtable();

		rootPoa = null;
		// rootPoa = new POA_impl(this, null, "RootPOA", null, null);
		//
		broadcaster = getServerBroadcaster(getDefautTransportProtocol());

	}

	public org.omg.CORBA.Object string_to_object(String str) {
		logger.debug("ORB::string_to_object(...)");

		IorParser ior = new IorParser(this, str);
		return ior.getObject();
	}

	public String object_to_string(org.omg.CORBA.Object obj) {
		logger.debug("ORB::object_to_string(...)");

		if (obj == null) {
			return null;
		}
		ObjRefDelegate delegate = (ObjRefDelegate) ((org.omg.CORBA.portable.ObjectImpl) obj)
				._get_delegate();

		String ior = delegate.toString();
		return ior;
	}

	public boolean get_service_information(short service_type,
			org.omg.CORBA.ServiceInformationHolder service_info) {
		logger.debug("ORB::get_service_information(...)");

		// we have no service supported here
		return false;
	}

	public String[] list_initial_services() {
		logger.debug("ORB::list_initial_services()");

		Vector v = new Vector();
		Enumeration e = initialReferences.keys();
		while (e.hasMoreElements()) {
			v.add(e.nextElement());
		}
		String[] initial_services = new String[services.length + v.size()];
		v.copyInto(initial_services);
		System.arraycopy(services, 0, initial_services, v.size(),
				services.length);
		return initial_services;
	}

	public void register_initial_reference(String object_name,
			org.omg.CORBA.Object object)
			throws org.omg.CORBA.ORBPackage.InvalidName {
		logger.debug("ORB::register_initial_reference(...)");

		if (object_name == null || object_name.length() == 0
				|| initialReferences.containsKey(object_name)) {
			throw new org.omg.CORBA.ORBPackage.InvalidName();
		} else {
			initialReferences.put(object_name, object);
		}
	}

	public org.omg.CORBA.Object resolve_initial_references(String object_name)
			throws org.omg.CORBA.ORBPackage.InvalidName {
		// logger.debug("ORB::resolve_initial_references(...)");

		if (initialReferences.containsKey(object_name)) {
			return (org.omg.CORBA.Object) initialReferences.get(object_name);
		} else if (object_name.equals("RootPOA")) {
			return (org.omg.CORBA.Object) getRootPOA();
		}
		// else if (object_name.equals("NameService")) {
		// return getNameServicePOA();
		// }
		else {
			// get initial references from elsewhere
			org.omg.CORBA.Object obj = broadcaster.resolveBinding(object_name);

			if (obj == null) {
				throw new org.omg.CORBA.ORBPackage.InvalidName();
			} else {
				return obj;
			}
		}
	}

	public void run() {
		logger.debug("ORB::run()");

		// implementation here
		java.lang.Thread handlerThread = new java.lang.Thread(handler);
		// java.lang.Thread listenerThread = new java.lang.Thread(listener);
		handlerThread.start();

		// listenerThread.start();
		listener.run();

	}

	public void shutdown(boolean wait_for_completion) {

		logger.debug("ORB::shutdown(...)");
		// do all works

	}

	public void destroy() {
		// logger.debug("ORB::destroy()");
	}

	public org.omg.CORBA.Policy create_policy(int type, org.omg.CORBA.Any val)
			throws org.omg.CORBA.PolicyError {
		// logger.debug("ORB::create_policy(...)");

		// implementation here
		throw new org.omg.CORBA.NO_IMPLEMENT();
	}

	public org.omg.CORBA.portable.OutputStream create_output_stream() {
		// logger.debug("ORB::create_output_stream(...)");

		return new CDROutputStream(this);
	}

	protected void set_parameters(String[] args, java.util.Properties props) {
		// logger.debug("ORB::set_parameters(...)");

		// implementation here
		initialize();
	}

	/**
	 * Get the Orbas Name Service from ior file.
	 * 
	 * @return org.omg.CORBA.Object
	 */
	protected org.omg.CORBA.Object getNameServicePOA() {
		// logger.debug("ORB::getNameServicePOA()");

		org.omg.CORBA.Object nameObj = null;
		try {
			String iorFile = "orbas_naming.ior";
			java.io.FileInputStream f = new java.io.FileInputStream(iorFile);
			byte[] buf = new byte[f.available()];

			f.read(buf, 0, f.available());
			String ior = new String(buf);

			org.omg.CORBA.Object obj = this.string_to_object(ior);
			// System.out.println("orb::obj="+obj);
			nameObj = obj;

		} catch (java.io.IOException ex) {
			ex.printStackTrace();
		}

		return nameObj;
	}

	public org.omg.CORBA.Object get_value_def(String repid) {
		throw new org.omg.CORBA.NO_IMPLEMENT();
	}

	public org.omg.CORBA.portable.ValueFactory register_value_factory(
			String id, org.omg.CORBA.portable.ValueFactory factory) {
		// implementation here
		return (org.omg.CORBA.portable.ValueFactory) valueFactories.put(id,
				factory);
	}

	public void unregister_value_factory(String id) {
		// implementation here
		valueFactories.remove(id);
	}

	public org.omg.CORBA.portable.ValueFactory lookup_value_factory(String id) {
		// implementation here
		logger.debug("ORB::lookup_value_factory(...)");

		org.omg.CORBA.portable.ValueFactory factory = null;
		factory = (org.omg.CORBA.portable.ValueFactory) valueFactories.get(id);

		if (factory == null) {
			if (id.startsWith("IDL")) {

				String baseName = id.substring(4, id.lastIndexOf(":"));

				baseName = baseName.replace('/', '.');

				String factoryName = baseName + "DefaultFactory";

				// load factory class
				try {
					Class ins = Class.forName(factoryName);
					factory = (org.omg.CORBA.portable.ValueFactory) (ins
							.newInstance());
					valueFactories.put(id, factory);
				} catch (ClassNotFoundException ec) {
					logger.debug(ec.toString());
				} catch (java.lang.InstantiationException ei) {
					logger.debug(ei.toString());
				} catch (java.lang.IllegalAccessException eill) {
					logger.debug(eill.toString());
				}
			}
		}

		return factory;
	}

	public void set_delegate(java.lang.Object wrapper) {
		// logger.debug("ORB::set_delegate(...)");

		// implementation here
		if (wrapper instanceof org.omg.PortableServer.Servant) {
			// set my own Delegate here

			// did we need multiple delegate instances?
			org.omg.PortableServer.Servant servant = (org.omg.PortableServer.Servant) wrapper;
			servant._set_delegate(new ServantDelegate(this));
		} else {
			throw new org.omg.CORBA.BAD_PARAM(0,
					org.omg.CORBA.CompletionStatus.COMPLETED_NO);
		}
	}

	public IorParser createIor(byte[] objectKey, String typeId) {
		// generating ior using default transport protocols
		// logger.debug("ORB::createIor(...)");

		org.omg.IOP.TaggedProfile[] profiles = profileDealers
				.getProfileCreator(getDefautTransportProtocol())
				.createProfiles(objectKey, getDefaultGiopVersion());

		IorParser parser = new IorParser(this, profiles, typeId);

		return parser;
	}

	public org.omg.CORBA.Any create_any() {
		// implementation here
		// logger.debug("ORB::create_any()");

		return new Any(this);
	}

	public OrbasPoa getRootPOA() {
		// load POA dynamically
		// logger.debug("ORB::getRootPOA()");

		if (rootPoa == null) {
			try {

				rootPoa = (OrbasPoa) (Class
						.forName("org.huihoo.orbas.poa.POAImpl").newInstance());
			} catch (ClassNotFoundException ec) {
				System.out.println(ec.toString());
			} catch (java.lang.InstantiationException ei) {
				System.out.println(ei.toString());
			} catch (java.lang.IllegalAccessException eill) {
				System.out.println(eill.toString());
			}
		}

		rootPoa.setOrb(this);

		return rootPoa;

	}

	public ProfileRegistry getProfileRegistry() {
		return profileDealers;
	}

	public ClientWorker getDefaultClientWorker(int version) {
		return new org.huihoo.orbas.orb.giop.GiopClientWorker(this, version);
	}

	public ServerWorker getDefaultServerWorker(Transport t) {
		return new org.huihoo.orbas.orb.giop.GiopServerWorker(this, t,
				getDefaultGiopVersion());
	}

	public TransportsPool getTransportsPool() {
		return pool;
	}

	public int getDefaultGiopVersion() {
		return 10;
	}

	public int getDefautTransportProtocol() {
		return 0;
	};

	public IopEngine getDefaultIopEngine() {
		return invoker;
	}

	public RequestQueue getRequestQueue() {
		return queue;
	}

	public OrbasPoa locatePoa(String id) {
		// change
		return (OrbasPoa) poaTable.get(id);
	}

	public void registerPoa(OrbasPoa poa, String id) {
		poaTable.put(id, poa);
	}

	public void unregisterPoa(String id) {
		poaTable.remove(id);
	}

	public ServerBroadcaster getServerBroadcaster(int protocolId) {
		ServerBroadcaster ret;
		ret = (ServerBroadcaster) serverBroadcasterFactory.get(new Integer(
				protocolId));

		return ret;
	}

	public void registerServerBroadcaster(int protocolId,
			ServerBroadcaster caster) {
		serverBroadcasterFactory.put(new Integer(protocolId), caster);

	}

	public org.omg.CORBA.Object binding(String name,
			org.omg.PortableServer.Servant servant) {
		if (casterThread == null) {
			casterThread = new java.lang.Thread(broadcaster);
			casterThread.start();
		}
		logger.debug("ORB::binding(...)");

		// System.out.println("Binding servant...");
		try {
			org.omg.PortableServer.POA poa = (org.omg.PortableServer.POA) getRootPOA();

			String[] ids = servant._all_interfaces(poa, null);
			org.omg.CORBA.Object ref = poa.servant_to_reference(servant);
			broadcaster.binding(name, ref);

			return ref;
		} catch (org.omg.PortableServer.POAPackage.ServantNotActive e) {
		} catch (org.omg.CORBA.ORBPackage.InvalidName e) {
		} catch (org.omg.PortableServer.POAPackage.WrongPolicy e) {
		}

		return null;
	}

	public org.omg.CORBA.Object resolve_binding(String name)
			throws org.omg.CORBA.ORBPackage.InvalidName {
		logger.debug("ORB::resolve_binding(...)");

		org.omg.CORBA.Object obj = broadcaster.resolveBinding(name);

		// return obj;
		if (obj == null) {
			throw new org.omg.CORBA.ORBPackage.InvalidName();
		} else {
			return obj;
		}
	}

}
